package com.zijidelu.luframework.infrastructure.factory.impl;

import com.zijidelu.luframework.base.TypeCaster;
import com.zijidelu.luframework.base.model.DataModel;
import com.zijidelu.luframework.base.model.PO;
import com.zijidelu.luframework.infrastructure.converter.DataConverter;
import com.zijidelu.luframework.infrastructure.factory.DataVault;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.bizsig.BizSigRepository;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.data.DataRepository;
import com.zijidelu.luframework.utils.cache.vault.AbstractGroupedVault;
import com.zijidelu.luframework.utils.cache.vault.SimpleVaultGroup;
import com.zijidelu.luframework.utils.spring.beans.generic.SpringBeanTypeUtil;
import com.zijidelu.luframework.utils.spring.beans.register.SpringSimpleBeanUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.core.ResolvableType;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Objects;

/**
 * 数据保险库 - 管理对象与数据模型之间的映射关系
 * <p>
 * 提供优雅的 API 来注册和查找对象与 DataModel、Repository 之间的映射关系。
 * 此类在应用启动时由扫描器写入映射数据，运行时为只读模式，仅提供查询功能。
 *
 * @author ZIJIDELU
 * @datetime 2025/11/19 01:07
 */
@Component
@RequiredArgsConstructor
public class DataVaultImpl extends AbstractGroupedVault<SimpleVaultGroup, Class<?>, Object> implements DataVault {
    private final SpringSimpleBeanUtil springSimpleBeanUtil;

    @Override
    protected void initializeVault() {
        // 初始化逻辑
    }

    /**
     * 获取数据模型到数据仓库的映射表
     * <p>
     * 存储 DataModel 到其对应 DataRepository 的映射关系
     */
    private Map<Class<? extends DataModel>, DataRepository<?, ? extends DataModel>> getModelToRepositoryMappings() {
        return getItem(SimpleVaultGroup.GROUP_0).selfCast();
    }

    /**
     * 获取数据模型到业务签名仓库的映射表
     * <p>
     * 存储 DataModel 到其对应 BizSigRepository 的映射关系
     */
    private Map<Class<? extends DataModel>, BizSigRepository<?, ? extends DataModel>> getModelToBizSigRepositoryMappings() {
        return getItem(SimpleVaultGroup.GROUP_1).selfCast();
    }

    // === 注册 API ===

    /**
     * 注册数据模型与数据仓库的映射关系
     * <p>
     * 此方法通常在应用启动时由扫描器调用
     *
     * @param dataModelClass 数据模型类型
     * @param repository     数据仓库实例
     */
    @Override
    public <P extends PO, D extends DataModel> void registerDataRepository(Class<D> dataModelClass,
                                                                           DataRepository<P, D> repository) {
        getModelToRepositoryMappings().put(dataModelClass, repository);
    }

    @Override
    public <P extends PO, D extends DataModel> void registerBizSigRepository(Class<D> dataModelClass, BizSigRepository<P, D> repository) {
        getModelToBizSigRepositoryMappings().put(dataModelClass, repository);
    }

    // === 查询 API ===

    /**
     * 获取指定对象类型对应的数据模型
     *
     * @param sourceClass 源对象类型
     * @return 对应的 DataModel 类型，未找到返回 null
     */
    public <D extends DataModel> Class<D> getDataModel(Class<?> sourceClass) {
        if (DataModel.class.isAssignableFrom(sourceClass)) {
            return TypeCaster.cast(sourceClass);
        }

        throw new IllegalArgumentException("Source class " + sourceClass + " does not have a corresponding DataModel");
    }

    /**
     * 获取指定数据模型对应的数据仓库
     *
     * @param dataModelClass 数据模型类型
     * @return 对应的数据仓库，未找到返回 null
     */
    @Override
    public <P extends PO, D extends DataModel> DataRepository<P, D> getDataRepository(Class<D> dataModelClass) {
        return TypeCaster.cast(getModelToRepositoryMappings().get(dataModelClass));
    }

    /**
     * 通过对象类型直接获取对应的数据仓库
     * <p>
     * 这是一个便捷方法，会自动先查找 DataModel，再查找对应的 Repository
     *
     * @param sourceClass 源对象类型
     * @return 对应的数据仓库，未找到返回 null
     */
    @Override
    public <P extends PO, D extends DataModel> DataRepository<P, D> getDataRepositoryFor(Class<?> sourceClass) {
        final Class<D> modelClass = getDataModel(sourceClass);
        return getDataRepository(modelClass);
    }

    /**
     * 获取指定数据模型对应的数据仓库
     *
     * @param dataModelClass 数据模型类型
     * @return 对应的数据仓库，未找到返回 null
     */
    @Override
    public <P extends PO, D extends DataModel> BizSigRepository<P, D> getBizSigRepository(Class<D> dataModelClass) {
        return TypeCaster.cast(getModelToBizSigRepositoryMappings().get(dataModelClass));
    }

    /**
     * 扫描并注册所有 DataRepository  bean
     * <p>
     * 此方法通常在应用启动时由扫描器调用
     */
    public void dataRepositoryScanner() {
        springSimpleBeanUtil.getBeansOfType(DataRepository.class).values()
                .forEach((bean) -> {
                    final ResolvableType beanResolvableType = ResolvableType.forInstance(bean);
                    final Class<?> beanClass = Objects.requireNonNull(beanResolvableType.resolve());
                    final String packageName = beanClass.getPackageName();
                    // 解析泛型参数
                    final ResolvableType[] resolvableTypes = SpringBeanTypeUtil.resolvableTargetClassTypes(bean, DataConverter.class);
                    final Class<?> poClass = Objects.requireNonNull(resolvableTypes[0].resolve());
                    final Class<? extends DataModel> dataModelClass = TypeCaster.cast(Objects.requireNonNull(resolvableTypes[1].resolve()));
                    // 注册映射关系
                    registerDataRepository(dataModelClass, TypeCaster.cast(bean));
                });
    }

}
